using Microsoft.EntityFrameworkCore;
using SheLife.Domain.Entities;
using SheLife.Domain.Interfaces.Repositories;
using SheLife.Infrastructure.Data;

namespace SheLife.Infrastructure.Repositories
{
    public class SkincareRecordRepository : Repository<SkincareRecord>, ISkincareRecordRepository
    {
        public SkincareRecordRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAndDateAsync(Guid userId, DateTime date)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.Date.Date == date.Date)
                .OrderBy(s => s.RecordTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.Date >= startDate && s.Date <= endDate)
                .OrderBy(s => s.Date)
                .ThenBy(s => s.RecordTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareRecord>> GetByUserIdAndSkinTypeAsync(Guid userId, string skinType)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.SkinType == skinType)
                .OrderByDescending(s => s.Date)
                .ThenBy(s => s.RecordTime)
                .ToListAsync();
        }
    }

    public class SkincareProductRepository : Repository<SkincareProduct>, ISkincareProductRepository
    {
        public SkincareProductRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareProduct>> GetByBrandAsync(string brand)
        {
            return await _dbSet
                .Where(s => s.Brand == brand)
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(s => s.Category == category)
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> SearchByNameAsync(string keyword)
        {
            return await _dbSet
                .Where(s => s.Name.Contains(keyword))
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareProduct>> GetByIngredientsAsync(IEnumerable<string> ingredients)
        {
            var ingredientList = ingredients.ToList();
            if (!ingredientList.Any())
                return new List<SkincareProduct>();

            return await _dbSet
                .Where(s => s.Ingredients.Any(i => ingredientList.Contains(i)))
                .OrderBy(s => s.Name)
                .ToListAsync();
        }
    }

    public class SkincareProductRecordRepository : Repository<SkincareProductRecord>, ISkincareProductRecordRepository
    {
        public SkincareProductRecordRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareProductRecord>> GetByUserIdAndDateRangeAsync(Guid userId, DateTime startDate, DateTime endDate)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.UseDate >= startDate && s.UseDate <= endDate)
                .OrderBy(s => s.UseDate)
                .ThenBy(s => s.UseTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareProductRecord>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet
                .Where(s => s.SkincareProductId == productId)
                .OrderByDescending(s => s.UseDate)
                .ThenByDescending(s => s.UseTime)
                .ToListAsync();
        }

        public async Task<SkincareProductRecord> GetLatestByUserIdAndProductIdAsync(Guid userId, Guid productId)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.SkincareProductId == productId)
                .OrderByDescending(s => s.UseDate)
                .ThenByDescending(s => s.UseTime)
                .FirstOrDefaultAsync();
        }
    }

    public class UserSkincareProductRepository : Repository<UserSkincareProduct>, IUserSkincareProductRepository
    {
        public UserSkincareProductRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserSkincareProduct>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.PurchaseDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserSkincareProduct>> GetByProductIdAsync(Guid productId)
        {
            return await _dbSet
                .Where(u => u.SkincareProductId == productId)
                .OrderByDescending(u => u.PurchaseDate)
                .ToListAsync();
        }

        public async Task<bool> IsUserProductExistsAsync(Guid userId, Guid productId)
        {
            return await _dbSet
                .AnyAsync(u => u.UserId == userId && u.SkincareProductId == productId);
        }
    }

    public class SkincareReminderRepository : Repository<SkincareReminder>, ISkincareReminderRepository
    {
        public SkincareReminderRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincareReminder>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(s => s.UserId == userId)
                .OrderBy(s => s.ReminderTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareReminder>> GetByUserIdAndIsActiveAsync(Guid userId, bool isActive)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.IsActive == isActive)
                .OrderBy(s => s.ReminderTime)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincareReminder>> GetByUserIdAndTimeAsync(Guid userId, TimeSpan time)
        {
            return await _dbSet
                .Where(s => s.UserId == userId && s.ReminderTime == time)
                .OrderBy(s => s.ReminderTime)
                .ToListAsync();
        }
    }

    public class SkincarePlanRepository : Repository<SkincarePlan>, ISkincarePlanRepository
    {
        public SkincarePlanRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincarePlan>> GetByCategoryAsync(string category)
        {
            return await _dbSet
                .Where(s => s.Category == category)
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> GetBySkinTypeAsync(string skinType)
        {
            return await _dbSet
                .Where(s => s.SkinType == skinType)
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> GetByDifficultyAsync(string difficulty)
        {
            return await _dbSet
                .Where(s => s.Difficulty == difficulty)
                .OrderBy(s => s.Name)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlan>> SearchByNameAsync(string keyword)
        {
            return await _dbSet
                .Where(s => s.Name.Contains(keyword))
                .OrderBy(s => s.Name)
                .ToListAsync();
        }
    }

    public class SkincarePlanStepRepository : Repository<SkincarePlanStep>, ISkincarePlanStepRepository
    {
        public SkincarePlanStepRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<SkincarePlanStep>> GetByPlanIdAsync(Guid planId)
        {
            return await _dbSet
                .Where(s => s.SkincarePlanId == planId)
                .ToListAsync();
        }

        public async Task<IEnumerable<SkincarePlanStep>> GetByPlanIdOrderByStepNumberAsync(Guid planId)
        {
            return await _dbSet
                .Where(s => s.SkincarePlanId == planId)
                .OrderBy(s => s.StepNumber)
                .ToListAsync();
        }
    }

    public class UserSkincarePlanRepository : Repository<UserSkincarePlan>, IUserSkincarePlanRepository
    {
        public UserSkincarePlanRepository(ApplicationDbContext context) : base(context)
        {
        }

        public async Task<IEnumerable<UserSkincarePlan>> GetByUserIdAsync(Guid userId)
        {
            return await _dbSet
                .Where(u => u.UserId == userId)
                .OrderByDescending(u => u.StartDate)
                .ToListAsync();
        }

        public async Task<IEnumerable<UserSkincarePlan>> GetByPlanIdAsync(Guid planId)
        {
            return await _dbSet
                .Where(u => u.SkincarePlanId == planId)
                .OrderByDescending(u => u.StartDate)
                .ToListAsync();
        }

        public async Task<bool> IsUserPlanExistsAsync(Guid userId, Guid planId)
        {
            return await _dbSet
                .AnyAsync(u => u.UserId == userId && u.SkincarePlanId == planId);
        }
    }
}